@param type: device type
"""
dominfo = self.domain_lookup(id)
- val = dominfo.device_delete(type, devid)
- dominfo.exportToDB()
- return val
+ return dominfo.destroyDevice(type, devid)
+
def domain_devtype_ls(self, id, type):
"""Get list of device sxprs for a domain.
-#============================================================================
+#===========================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
"""
-import string, re
-import os
+import string
import time
import threading
import errno
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
-from xen.util.ip import check_subnet, get_current_ipgw
from xen.util.blkif import blkdev_uname_to_file
-from xen.xend.server import controller
from xen.xend.server import SrvDaemon; xend = SrvDaemon.instance()
from xen.xend.server.channel import EventChannel
-from xen.util.blkif import blkdev_name_to_number, expand_dev_name
from xen.xend import sxp
-from xen.xend import Blkctl
from xen.xend.PrettyPrint import prettyprintstring
from xen.xend.XendBootloader import bootloader
from xen.xend.XendLogging import log
from xen.xend.XendRoot import get_component
from xen.xend.uuid import getUuid
-from xen.xend.xenstore import DBVar, XenNode, DBMap
+from xen.xend.xenstore import DBVar
from xen.xend.xenstore.xstransact import xstransact
from xen.xend.xenstore.xsutil import IntroduceDomain
self.store_mfn = None
self.console_channel = None
self.console_mfn = None
- self.controllers = {}
self.info = None
self.backend_flags = 0
- self.netif_idx = 0
#todo: state: running, suspended
self.state = STATE_VM_OK
def getName(self):
return self.name
+ def getPath(self):
+ return self.path
+
+ def getUuid(self):
+ return self.uuid
+
def getVCpuCount(self):
return self.vcpus
__repr__ = __str__
- def getDeviceController(self, type, error=True):
- ctrl = self.controllers.get(type)
- if not ctrl and error:
- raise XendError("invalid device type:" + type)
- return ctrl
-
- def findDeviceController(self, type):
- return (self.getDeviceController(type, error=False)
- or self.createDeviceController(type))
- def createDeviceController(self, type):
- ctrl = controller.createDevController(type, self, recreate=self.recreate)
- self.controllers[type] = ctrl
- return ctrl
+ def getDeviceController(self, name):
+ if name not in controllerClasses:
+ raise XendError("unknown device type: " + str(name))
- def createDevice(self, type, devconfig, change=False):
- if self.recreate:
- return
- if type == 'vbd':
- typedev = sxp.child_value(devconfig, 'dev')
- if re.match('^ioemu:', typedev):
- return;
-
- backdom = domain_exists(sxp.child_value(devconfig, 'backend', '0'))
-
- devnum = blkdev_name_to_number(sxp.child_value(devconfig, 'dev'))
-
- backpath = "%s/backend/%s/%s/%d" % (backdom.path, type,
- self.uuid, devnum)
- frontpath = "%s/device/%s/%d" % (self.path, type, devnum)
-
- front = { 'backend' : backpath,
- 'backend-id' : "%i" % backdom.domid,
- 'virtual-device' : "%i" % devnum }
- xstransact.Write(frontpath, front)
-
- (type, params) = string.split(sxp.child_value(devconfig,
- 'uname'), ':', 1)
- readonly = sxp.child_value(devconfig, 'mode', 'r')
- back = { 'type' : type,
- 'params' : params,
- 'frontend' : frontpath,
- 'frontend-id' : "%i" % self.domid }
- if readonly == 'r':
- back['read-only'] = "" # existence indicates read-only
- xstransact.Write(backpath, back)
+ return controllerClasses[name](self)
- return
- if type == 'vif':
- from xen.xend import XendRoot
- xroot = XendRoot.instance()
-
- def _get_config_ipaddr(config):
- val = []
- for ipaddr in sxp.children(config, elt='ip'):
- val.append(sxp.child0(ipaddr))
- return val
-
- backdom = domain_exists(sxp.child_value(devconfig, 'backend', '0'))
-
- devnum = self.netif_idx
- self.netif_idx += 1
-
- script = sxp.child_value(devconfig, 'script',
- xroot.get_vif_script())
- script = os.path.join(xroot.network_script_dir, script)
- bridge = sxp.child_value(devconfig, 'bridge',
- xroot.get_vif_bridge())
- mac = sxp.child_value(devconfig, 'mac')
- ipaddr = _get_config_ipaddr(devconfig)
-
- backpath = "%s/backend/%s/%s/%d" % (backdom.path, type,
- self.uuid, devnum)
- frontpath = "%s/device/%s/%d" % (self.path, type, devnum)
-
- front = { 'backend' : backpath,
- 'backend-id' : "%i" % backdom.domid,
- 'handle' : "%i" % devnum,
- 'mac' : mac }
- xstransact.Write(frontpath, front)
-
- back = { 'script' : script,
- 'domain' : self.name,
- 'mac' : mac,
- 'bridge' : bridge,
- 'frontend' : frontpath,
- 'frontend-id' : "%i" % self.domid,
- 'handle' : "%i" % devnum }
- if ipaddr:
- back['ip'] = ' '.join(ipaddr)
- xstransact.Write(backpath, back)
+ def createDevice(self, deviceClass, devconfig):
+ return self.getDeviceController(deviceClass).createDevice(devconfig)
- return
-
- if type == 'vtpm':
- backdom = domain_exists(sxp.child_value(devconfig, 'backend', '0'))
- devnum = int(sxp.child_value(devconfig, 'instance', '0'))
- log.error("The domain has a TPM with instance %d." % devnum)
+ def configureDevice(self, deviceClass, devid, devconfig):
+ return self.getDeviceController(deviceClass).configureDevice(
+ devid, devconfig)
- backpath = "%s/backend/%s/%s/%d" % (backdom.path, type,
- self.uuid, devnum)
- frontpath = "%s/device/%s/%d" % (self.path, type, devnum)
- front = { 'backend' : backpath,
- 'backend-id' : "%i" % backdom.domid,
- 'handle' : "%i" % devnum }
- xstransact.Write(frontpath, front)
+ def destroyDevice(self, deviceClass, devid):
+ return self.getDeviceController(deviceClass).destroyDevice(devid)
- back = { 'instance' : "%i" % devnum,
- 'frontend' : frontpath,
- 'frontend-id' : "%i" % self.domid }
- xstransact.Write(backpath, back)
-
- return
-
- ctrl = self.findDeviceController(type)
- return ctrl.createDevice(devconfig, recreate=self.recreate,
- change=change)
-
- def configureDevice(self, type, id, devconfig):
- ctrl = self.getDeviceController(type)
- return ctrl.configureDevice(id, devconfig)
-
- def destroyDevice(self, type, id, change=False, reboot=False):
- ctrl = self.getDeviceController(type)
- return ctrl.destroyDevice(id, change=change, reboot=reboot)
-
- def deleteDevice(self, type, id):
- ctrl = self.getDeviceController(type)
- return ctrl.deleteDevice(id)
-
- def getDevice(self, type, id, error=True):
- ctrl = self.getDeviceController(type)
- return ctrl.getDevice(id, error=error)
-
- def getDeviceIds(self, type):
- ctrl = self.getDeviceController(type)
- return ctrl.getDeviceIds()
-
- def getDeviceSxprs(self, type):
- ctrl = self.getDeviceController(type)
- return ctrl.getDeviceSxprs()
def sxpr(self):
sxpr = ['domain',
sxpr.append(['restart_state', self.restart_state])
if self.restart_time:
sxpr.append(['restart_time', str(self.restart_time)])
-
- devs = self.sxpr_devices()
- if devs:
- sxpr.append(devs)
if self.config:
sxpr.append(['config', self.config])
return sxpr
- def sxpr_devices(self):
- sxpr = []
- for ty in self.controllers.keys():
- devs = self.getDeviceSxprs(ty)
- sxpr += devs
- if sxpr:
- sxpr.insert(0, 'devices')
- else:
- sxpr = None
- return sxpr
-
def check_name(self, name):
"""Check if a vm name is valid. Valid names contain alphabetic characters,
digits, or characters in '_-.:/+'.
def release_devices(self):
"""Release all vm devices.
"""
- reboot = self.restart_pending()
- for ctrl in self.controllers.values():
- if ctrl.isDestroyed(): continue
- ctrl.destroyController(reboot=reboot)
+
t = xstransact("%s/device" % self.path)
- for d in t.list("vbd"):
- t.remove(d)
- for d in t.list("vif"):
- t.remove(d)
- for d in t.list("vtpm"):
- t.remove(d)
+ for n in controllerClasses.keys():
+ for d in t.list(n):
+ try:
+ t.remove(d)
+ except ex:
+ # Log and swallow any exceptions in removal -- there's
+ # nothing more we can do.
+ log.exception(
+ "Device release failed: %s; %s; %s; %s" %
+ (self.info['name'], n, d, str(ex)))
t.commit()
+
def show(self):
"""Print virtual machine info.
"""
raise VmError('invalid device')
dev_type = sxp.name(dev_config)
- if not controller.isDevControllerClass(dev_type):
- raise VmError('unknown device type: ' + dev_type)
-
self.createDevice(dev_type, dev_config)
@raise: VmError for invalid devices
"""
- if self.rebooting():
- for ctrl in self.controllers.values():
- ctrl.initController(reboot=True)
- else:
+ if not self.rebooting():
self.create_configured_devices()
self.image.createDeviceModel()
@param dev_config: device configuration
"""
dev_type = sxp.name(dev_config)
- dev = self.createDevice(dev_type, dev_config, change=True)
- self.config.append(['device', dev.getConfig()])
- return dev.sxpr()
+ devid = self.createDevice(dev_type, dev_config)
+# self.config.append(['device', dev.getConfig()])
+ return self.getDeviceController(dev_type).sxpr(devid)
- def device_configure(self, dev_config, id):
- """Configure an existing device.
+ def device_configure(self, dev_config, devid):
+ """Configure an existing device.
@param dev_config: device configuration
- @param id: device id
- """
- type = sxp.name(dev_config)
- dev = self.getDevice(type, id)
- old_config = dev.getConfig()
- new_config = dev.configure(dev_config, change=True)
- # Patch new config into vm config.
- new_full_config = ['device', new_config]
- old_full_config = ['device', old_config]
- old_index = self.config.index(old_full_config)
- self.config[old_index] = new_full_config
- return new_config
-
- def device_refresh(self, type, id):
- """Refresh a device.
-
- @param type: device type
- @param id: device id
+ @param devid: device id
"""
- dev = self.getDevice(type, id)
- dev.refresh()
-
- def device_delete(self, type, id):
- """Destroy and remove a device.
+ deviceClass = sxp.name(dev_config)
+ self.configureDevice(deviceClass, devid, dev_config)
- @param type: device type
- @param id: device id
- """
- dev = self.getDevice(type, id)
- dev_config = dev.getConfig()
- if dev_config:
- self.config.remove(['device', dev_config])
- self.deleteDevice(type, dev.getId())
def configure_restart(self):
"""Configure the vm restart mode.
"""
return
- blkif = self.getDeviceController("vbd", error=False)
- if not blkif:
- blkif = self.createDeviceController("vbd")
- backend = blkif.getBackend(0)
- backend.connect(recreate=self.recreate)
def configure_fields(self):
"""Process the vm configuration fields using the registered handlers.
#============================================================================
# Register device controllers and their device config types.
+"""A map from device-class names to the subclass of DevController that
+implements the device control specific to that device-class."""
+controllerClasses = {}
+
+
+def addControllerClass(device_class, cls):
+ """Register a subclass of DevController to handle the named device-class.
+ """
+ cls.deviceClass = device_class
+ controllerClasses[device_class] = cls
+
+
from xen.xend.server import blkif, netif, tpmif, pciif, usbif
-controller.addDevControllerClass("vbd", blkif.BlkifController)
-controller.addDevControllerClass("vif", netif.NetifController)
-controller.addDevControllerClass("vtpm", tpmif.TPMifController)
-controller.addDevControllerClass("pci", pciif.PciController)
-controller.addDevControllerClass("usb", usbif.UsbifController)
+addControllerClass('vbd', blkif.BlkifController)
+addControllerClass('vif', netif.NetifController)
+addControllerClass('vtpm', tpmif.TPMifController)
+addControllerClass('pci', pciif.PciController)
+addControllerClass('usb', usbif.UsbifController)
--- /dev/null
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
+# Copyright (C) 2005 XenSource Ltd
+#============================================================================
+
+
+from xen.xend import sxp
+from xen.xend.XendError import VmError
+from xen.xend.XendLogging import log
+from xen.xend.xenstore.xstransact import xstransact
+
+
+class DevController:
+ """Abstract base class for a device controller. Device controllers create
+ appropriate entries in the store to trigger the creation, reconfiguration,
+ and destruction of devices in guest domains. Each subclass of
+ DevController is responsible for a particular device-class, and
+ understands the details of configuration specific to that device-class.
+
+ DevController itself provides the functionality common to all device
+ creation tasks, as well as providing an interface to XendDomainInfo for
+ triggering those events themselves.
+ """
+
+ # Set when registered.
+ deviceClass = None
+
+
+ ## public:
+
+ def __init__(self, vm):
+ self.vm = vm
+
+
+ def createDevice(self, config):
+ """Trigger the creation of a device with the given configuration.
+
+ @return The ID for the newly created device.
+ """
+ (devid, back, front) = self.getDeviceDetails(config)
+
+ self.writeDetails(config, devid, back, front)
+
+ return devid
+
+
+ def reconfigureDevice(self, devid, config):
+ """Reconfigure the specified device.
+
+ The implementation here just raises VmError. This may be overridden
+ by those subclasses that can reconfigure their devices.
+ """
+ raise VmError('%s devices may not be reconfigured' % self.deviceClass)
+
+
+ def destroyDevice(self, devid):
+ """Destroy the specified device.
+
+ The implementation here simply deletes the appropriate paths from
+ the store. This may be overridden by subclasses who need to perform
+ other tasks on destruction.
+ """
+
+ frontpath = self.frontendPath(devid)
+ backpath = xstransact.Read("%s/backend" % frontpath)
+
+ xstransact.Remove(frontpath)
+ xstransact.Remove(backpath)
+
+
+ def sxpr(self, devid):
+ """@return an s-expression describing the specified device.
+ """
+ return [self.deviceClass, ['dom', self.vm.getDomain(),
+ 'id', devid]]
+
+
+ ## protected:
+
+ def getDeviceDetails(self, config):
+ """Compute the details for creation of a device corresponding to the
+ given configuration. These details consist of a tuple of (devID,
+ backDetails, frontDetails), where devID is the ID for the new device,
+ and backDetails and frontDetails are the device configuration
+ specifics for the backend and frontend respectively.
+
+ backDetails and frontDetails should be dictionaries, the keys and
+ values of which will be used as paths in the store. There is no need
+ for these dictionaries to include the references from frontend to
+ backend, nor vice versa, as these will be handled by DevController.
+
+ Abstract; must be implemented by every subclass.
+
+ @return (devID, backDetails, frontDetails), as specified above.
+ """
+
+ raise NotImplementedError()
+
+
+ def getDomain(self):
+ """Stub to {@link XendDomainInfo.getDomain}, for use by our
+ subclasses.
+ """
+ return self.vm.getDomain()
+
+
+ ## private:
+
+ def writeDetails(self, config, devid, backDetails, frontDetails):
+ """Write the details in the store to trigger creation of a device.
+ The backend domain ID is taken from the given config, paths for
+ frontend and backend are computed, and these are written to the store
+ appropriately, including references from frontend to backend and vice
+ versa.
+
+ @param config The configuration of the device, as given to
+ {@link #createDevice}.
+ @param devid As returned by {@link #getDeviceDetails}.
+ @param backDetails As returned by {@link #getDeviceDetails}.
+ @param frontDetails As returned by {@link #getDeviceDetails}.
+ """
+
+ import xen.xend.XendDomain
+ backdom = xen.xend.XendDomain.instance().domain_lookup_by_name(
+ sxp.child_value(config, 'backend', '0'))
+
+ frontpath = self.frontendPath(devid)
+ backpath = self.backendPath(backdom, devid)
+
+ frontDetails.update({
+ 'backend' : backpath,
+ 'backend-id' : "%i" % backdom.getDomain()
+ })
+
+
+ backDetails.update({
+ 'domain' : self.vm.getName(),
+ 'frontend' : frontpath,
+ 'frontend-id' : "%i" % self.vm.getDomain()
+ })
+
+ log.debug('DevController: writing %s to %s.', str(frontDetails),
+ frontpath)
+ log.debug('DevController: writing %s to %s.', str(backDetails),
+ backpath)
+
+ xstransact.Write(frontpath, frontDetails)
+ xstransact.Write(backpath, backDetails)
+
+
+ def backendPath(self, backdom, devid):
+ """@param backdom [XendDomainInfo] The backend domain info."""
+
+ return "%s/backend/%s/%s/%d" % (backdom.getPath(),
+ self.deviceClass,
+ self.vm.getUuid(), devid)
+
+
+ def frontendPath(self, devid):
+ return "%s/device/%s/%d" % (self.vm.getPath(),
+ self.deviceClass,
+ devid)
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
+# Copyright (C) 2005 XenSource Ltd
#============================================================================
-"""Support for virtual block devices.
-"""
+
+import re
import string
from xen.util import blkif
-from xen.xend.XendError import XendError, VmError
-from xen.xend.XendRoot import get_component
-from xen.xend.XendLogging import log
from xen.xend import sxp
-from xen.xend import Blkctl
-from xen.xend.xenstore import DBVar
-
-from xen.xend.server.controller import Dev, DevController
-
-class BlkifBackend:
- """ Handler for the 'back-end' channel to a block device driver domain
- on behalf of a front-end domain.
- Must be connected using connect() before it can be used.
- """
-
- def __init__(self, controller, id, dom, recreate=False):
- self.controller = controller
- self.id = id
- self.frontendDomain = self.controller.getDomain()
- self.backendDomain = dom
- self.destroyed = False
- self.connected = False
- self.status = None
-
- def init(self, recreate=False, reboot=False):
- self.destroyed = False
- self.status = BLKIF_INTERFACE_STATUS_DISCONNECTED
- self.frontendDomain = self.controller.getDomain()
-
- def __str__(self):
- return ('<BlkifBackend frontend=%d backend=%d id=%d>'
- % (self.frontendDomain,
- self.backendDomain,
- self.id))
-
- def getId(self):
- return self.id
-
- def connect(self, recreate=False):
- """Connect to the blkif control interface.
-
- @param recreate: true if after xend restart
- """
- log.debug("Connecting blkif %s", str(self))
- if recreate or self.connected:
- self.connected = True
- pass
-
- def destroy(self, change=False, reboot=False):
- """Disconnect from the blkif control interface and destroy it.
- """
- self.destroyed = True
- # For change true need to notify front-end, or back-end will do it?
-
- def connectInterface(self, val):
- self.status = BLKIF_INTERFACE_STATUS_CONNECTED
-
- def interfaceDisconnected(self):
- self.status = BLKIF_INTERFACE_STATUS_DISCONNECTED
-
-class BlkDev(Dev):
- """Info record for a block device.
- """
-
- __exports__ = Dev.__exports__ + [
- DBVar('dev', ty='str'),
- DBVar('vdev', ty='int'),
- DBVar('mode', ty='str'),
- DBVar('viftype', ty='str'),
- DBVar('params', ty='str'),
- DBVar('node', ty='str'),
- DBVar('device', ty='long'),
- DBVar('dev_handle', ty='long'),
- DBVar('start_sector', ty='long'),
- DBVar('nr_sectors', ty='long'),
- ]
-
- def __init__(self, controller, id, config, recreate=False):
- Dev.__init__(self, controller, id, config, recreate=recreate)
- self.dev = None
- self.uname = None
- self.vdev = None
- self.mode = None
- self.type = None
- self.params = None
- self.node = None
- self.device = None
- self.dev_handle = 0
- self.start_sector = None
- self.nr_sectors = None
-
- self.frontendDomain = self.getDomain()
- self.backendDomain = None
- self.backendId = 0
- self.configure(self.config, recreate=recreate)
-
- def exportToDB(self, save=False):
- Dev.exportToDB(self, save=save)
- backend = self.getBackend()
-
- def init(self, recreate=False, reboot=False):
- self.frontendDomain = self.getDomain()
- backend = self.getBackend()
- self.backendId = backend.domid
-
- def configure(self, config, change=False, recreate=False):
- if change:
- raise XendError("cannot reconfigure vbd")
- self.config = config
- self.uname = sxp.child_value(config, 'uname')
- if not self.uname:
- raise VmError('vbd: Missing uname')
- # Split into type and type-specific params (which are passed to the
- # type-specific control script).
- (self.type, self.params) = string.split(self.uname, ':', 1)
- self.dev = sxp.child_value(config, 'dev')
- if not self.dev:
- raise VmError('vbd: Missing dev')
- self.mode = sxp.child_value(config, 'mode', 'r')
-
- self.vdev = blkif.blkdev_name_to_number(self.dev)
- if not self.vdev:
- raise VmError('vbd: Device not found: %s' % self.dev)
-
- try:
- xd = get_component('xen.xend.XendDomain')
- self.backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).domid
- except:
- raise XendError('invalid backend domain')
- return self.config
+from xen.xend.server.DevController import DevController
- def attach(self, recreate=False, change=False):
- if recreate:
- pass
- else:
- node = Blkctl.block('bind', self.type, self.params)
- self.setNode(node)
- self.attachBackend()
- if change:
- self.interfaceChanged()
- def unbind(self):
- if self.node is None: return
- log.debug("Unbinding vbd (type %s) from %s"
- % (self.type, self.node))
- Blkctl.block('unbind', self.type, self.node)
-
- def setNode(self, node):
-
- # NOTE:
- # This clause is testing code for storage system experiments.
- # Add a new disk type that will just pass an opaque id in the
- # dev_handle and use an experimental device type.
- # Please contact andrew.warfield@cl.cam.ac.uk with any concerns.
- if self.type == 'parallax':
- self.node = node
- self.device = 61440 # (240,0)
- self.dev_handle = long(self.params)
- self.nr_sectors = long(0)
- return
- # done.
-
- mounted_mode = self.check_mounted(node)
- if not '!' in self.mode and mounted_mode:
- if mounted_mode == "w":
- raise VmError("vbd: Segment %s is in writable use" %
- self.uname)
- elif 'w' in self.mode:
- raise VmError("vbd: Segment %s is in read-only use" %
- self.uname)
-
- segment = blkif.blkdev_segment(node)
- if not segment:
- raise VmError("vbd: Segment not found: uname=%s" % self.uname)
- self.node = node
- self.device = segment['device']
- self.start_sector = segment['start_sector']
- self.nr_sectors = segment['nr_sectors']
-
- def check_mounted(self, name):
- mode = blkif.mount_mode(name)
- xd = get_component('xen.xend.XendDomain')
- for vm in xd.list():
- ctrl = vm.getDeviceController(self.getType(), error=False)
- if (not ctrl): continue
- for dev in ctrl.getDevices():
- if dev is self: continue
- if dev.type == 'phy' and name == blkif.expand_dev_name(dev.params):
- mode = dev.mode
- if 'w' in mode:
- return 'w'
- if mode and 'r' in mode:
- return 'r'
- return None
-
- def readonly(self):
- return 'w' not in self.mode
-
- def sxpr(self):
- val = ['vbd',
- ['id', self.id],
- ['vdev', self.vdev],
- ['device', self.device],
- ['mode', self.mode]]
- if self.dev:
- val.append(['dev', self.dev])
- if self.uname:
- val.append(['uname', self.uname])
- if self.node:
- val.append(['node', self.node])
- return val
-
- def getBackend(self):
- return self.controller.getBackend(self.backendDomain)
-
- def refresh(self):
- log.debug("Refreshing vbd domain=%d id=%s", self.frontendDomain,
- self.id)
- self.interfaceChanged()
-
- def destroy(self, change=False, reboot=False):
- """Destroy the device. If 'change' is true notify the front-end interface.
-
- @param change: change flag
- """
- self.destroyed = True
- log.debug("Destroying vbd domain=%d id=%s", self.frontendDomain,
- self.id)
- if change:
- self.interfaceChanged()
- self.unbind()
-
- def interfaceChanged(self):
- """Tell the back-end to notify the front-end that a device has been
- added or removed.
- """
- self.getBackend().interfaceChanged()
-
- def attachBackend(self):
- """Attach the device to its controller.
-
- """
- self.getBackend().connect()
-
class BlkifController(DevController):
"""Block device interface controller. Handles all block devices
for a domain.
"""
- def __init__(self, vm, recreate=False):
+ def __init__(self, vm):
"""Create a block device controller.
"""
- DevController.__init__(self, vm, recreate=recreate)
- self.backends = {}
- self.backendId = 0
-
- def initController(self, recreate=False, reboot=False):
- self.destroyed = False
- if reboot:
- self.rebootBackends()
- self.rebootDevices()
+ DevController.__init__(self, vm)
- def sxpr(self):
- val = ['blkif', ['dom', self.getDomain()]]
- return val
- def rebootBackends(self):
- for backend in self.backends.values():
- backend.init(reboot=True)
-
- def getBackendById(self, id):
- return self.backends.get(id)
+ def getDeviceDetails(self, config):
+ """@see DevController.getDeviceDetails"""
+
+ typedev = sxp.child_value(config, 'dev')
+ if re.match('^ioemu:', typedev):
+ return
- def getBackendByDomain(self, dom):
- for backend in self.backends.values():
- if backend.backendDomain == dom:
- return backend
- return None
+ devid = blkif.blkdev_name_to_number(sxp.child_value(config, 'dev'))
- def getBackend(self, dom):
- backend = self.getBackendByDomain(dom)
- if backend: return backend
- backend = BlkifBackend(self, self.backendId, dom)
- self.backendId += 1
- self.backends[backend.getId()] = backend
- backend.init()
- return backend
+ (typ, params) = string.split(sxp.child_value(config, 'uname'), ':', 1)
+ back = { 'type' : typ,
+ 'params' : params
+ }
- def newDevice(self, id, config, recreate=False):
- """Create a device..
+ if 'r' == sxp.child_value(config, 'mode', 'r'):
+ back['read-only'] = "" # existence indicates read-only
- @param id: device id
- @param config: device configuration
- @param recreate: if true it's being recreated (after xend restart)
- @type recreate: bool
- @return: device
- @rtype: BlkDev
- """
- return BlkDev(self, id, config, recreate=recreate)
-
- def destroyController(self, reboot=False):
- """Destroy the controller and all devices.
- """
- self.destroyed = True
- log.debug("Destroying blkif domain=%d", self.getDomain())
- self.destroyDevices(reboot=reboot)
- self.destroyBackends(reboot=reboot)
+ front = { 'virtual-device' : "%i" % devid }
- def destroyBackends(self, reboot=False):
- for backend in self.backends.values():
- backend.destroy(reboot=reboot)
+ return (devid, back, front)
+++ /dev/null
-#============================================================================
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of version 2.1 of the GNU Lesser General Public
-# License as published by the Free Software Foundation.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#============================================================================
-# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
-#============================================================================
-
-"""General support for controllers, which handle devices
-for a domain.
-"""
-
-from xen.xend.XendError import XendError
-from xen.xend.xenstore import DBVar
-
-DEBUG = 0
-
-class DevControllerTable:
- """Table of device controller classes, indexed by type name.
- """
-
- def __init__(self):
- self.controllerClasses = {}
-
- def getDevControllerClass(self, type):
- return self.controllerClasses.get(type)
-
- def addDevControllerClass(self, cls):
- self.controllerClasses[cls.getType()] = cls
-
- def delDevControllerClass(self, type):
- if type in self.controllerClasses:
- del self.controllerClasses[type]
-
- def createDevController(self, type, vm, recreate=False):
- cls = self.getDevControllerClass(type)
- if not cls:
- raise XendError("unknown device type: " + str(type))
- return cls.createDevController(vm, recreate=recreate)
-
-def getDevControllerTable():
- """Singleton constructor for the controller table.
- """
- global devControllerTable
- try:
- devControllerTable
- except:
- devControllerTable = DevControllerTable()
- return devControllerTable
-
-def addDevControllerClass(name, cls):
- """Add a device controller class to the controller table.
- """
- cls.type = name
- getDevControllerTable().addDevControllerClass(cls)
-
-
-def isDevControllerClass(name):
- """@return True if a device controller class has been registered with
- the controller table under the given name."""
- return name in getDevControllerTable().controllerClasses
-
-
-def createDevController(name, vm, recreate=False):
- return getDevControllerTable().createDevController(name, vm, recreate=recreate)
-
-class DevController:
- """Abstract class for a device controller attached to a domain.
- A device controller manages all the devices of a given type for a domain.
- There is exactly one device controller for each device type for
- a domain.
-
- """
-
- # State:
- # controller/<type> : for controller
- # device/<type>/<id> : for each device
-
- def createDevController(cls, vm, recreate=False):
- """Class method to create a dev controller.
- """
- ctrl = cls(vm, recreate=recreate)
- ctrl.initController(recreate=recreate)
- ctrl.exportToDB()
- return ctrl
-
- createDevController = classmethod(createDevController)
-
- def getType(cls):
- return cls.type
-
- getType = classmethod(getType)
-
- __exports__ = [
- DBVar('type', 'str'),
- DBVar('destroyed', 'bool'),
- ]
-
- # Set when registered.
- type = None
-
- def __init__(self, vm, recreate=False):
- self.destroyed = False
- self.vm = vm
- self.db = self.getDB()
- self.deviceId = 0
- self.devices = {}
- self.device_order = []
-
- def getDB(self):
- """Get the db node to use for a controller.
- """
- return self.vm.db.addChild("/controller/%s" % self.getType())
-
- def getDevDB(self, id):
- """Get the db node to use for a device.
- """
- return self.vm.db.addChild("/device/%s/%s" % (self.getType(), id))
-
- def exportToDB(self, save=False):
- self.db.exportToDB(self, fields=self.__exports__, save=save)
-
- def importFromDB(self):
- self.db.importFromDB(self, fields=self.__exports__)
-
- def getDevControllerType(self):
- return self.dctype
-
- def getDomain(self):
- return self.vm.getDomain()
-
- def getDomainName(self):
- return self.vm.getName()
-
- def getDomainInfo(self):
- return self.vm
-
- #----------------------------------------------------------------------------
- # Subclass interface.
- # Subclasses should define the unimplemented methods..
- # Redefinitions must have the same arguments.
-
- def initController(self, recreate=False, reboot=False):
- """Initialise the controller. Called when the controller is
- first created, and again after the domain is rebooted (with reboot True).
- If called with recreate True (and reboot False) the controller is being
- recreated after a xend restart.
-
- As this can be a re-init (after reboot) any controller state should
- be reset. For example the destroyed flag.
- """
- self.destroyed = False
- if reboot:
- self.rebootDevices()
-
- def newDevice(self, id, config, recreate=False):
- """Create a device with the given config.
- Must be defined in subclass.
- Called with recreate True when the device is being recreated after a
- xend restart.
-
- @return device
- """
- raise NotImplementedError()
-
- def createDevice(self, config, recreate=False, change=False):
- """Create a device and attach to its front- and back-ends.
- If recreate is true the device is being recreated after a xend restart.
- If change is true the device is a change to an existing domain,
- i.e. it is being added at runtime rather than when the domain is created.
- """
- dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate)
- if self.vm.recreate:
- dev.importFromDB()
- dev.init(recreate=recreate)
- self.addDevice(dev)
- if not recreate:
- dev.exportToDB()
- dev.attach(recreate=recreate, change=change)
- dev.exportToDB()
-
- return dev
-
- def configureDevice(self, id, config, change=False):
- """Reconfigure an existing device.
- May be defined in subclass."""
- dev = self.getDevice(id, error=True)
- dev.configure(config, change=change)
-
- def destroyDevice(self, id, change=False, reboot=False):
- """Destroy a device.
- May be defined in subclass.
-
- If reboot is true the device is being destroyed for a domain reboot.
-
- The device is not deleted, since it may be recreated later.
- """
- dev = self.getDevice(id, error=True)
- dev.destroy(change=change, reboot=reboot)
- return dev
-
- def deleteDevice(self, id, change=True):
- """Destroy a device and delete it.
- Normally called to remove a device from a domain at runtime.
- """
- dev = self.destroyDevice(id, change=change)
- self.removeDevice(dev)
-
- def destroyController(self, reboot=False):
- """Destroy all devices and clean up.
- May be defined in subclass.
- If reboot is true the controller is being destroyed for a domain reboot.
- Called at domain shutdown.
- """
- self.destroyed = True
- self.destroyDevices(reboot=reboot)
-
- #----------------------------------------------------------------------------
-
- def isDestroyed(self):
- return self.destroyed
-
- def getDevice(self, id, error=False):
- dev = self.devices.get(int(id))
- if error and not dev:
- raise XendError("invalid device id: " + str(id))
- return dev
-
- def getDeviceIds(self):
- return [ dev.getId() for dev in self.device_order ]
-
- def getDevices(self):
- return self.device_order
-
- def getDeviceConfig(self, id):
- return self.getDevice(id).getConfig()
-
- def getDeviceConfigs(self):
- return [ dev.getConfig() for dev in self.device_order ]
-
- def getDeviceSxprs(self):
- return [ dev.sxpr() for dev in self.device_order ]
-
- def addDevice(self, dev):
- self.devices[dev.getId()] = dev
- self.device_order.append(dev)
- return dev
-
- def removeDevice(self, dev):
- if dev.getId() in self.devices:
- del self.devices[dev.getId()]
- if dev in self.device_order:
- self.device_order.remove(dev)
-
- def rebootDevices(self):
- for dev in self.getDevices():
- dev.reboot()
-
- def destroyDevices(self, reboot=False):
- """Destroy all devices.
- """
- for dev in self.getDevices():
- dev.destroy(reboot=reboot)
-
- def getMaxDeviceId(self):
- maxid = 0
- for id in self.devices:
- if id > maxid:
- maxid = id
- return maxid
-
- def nextDeviceId(self):
- id = self.deviceId
- self.deviceId += 1
- return id
-
- def getDeviceCount(self):
- return len(self.devices)
-
-class Dev:
- """Abstract class for a device attached to a device controller.
-
- @ivar id: identifier
- @type id: int
- @ivar controller: device controller
- @type controller: DevController
- """
-
- # ./status : need 2: actual and requested?
- # down-down: initial.
- # up-up: fully up.
- # down-up: down requested, still up. Watch front and back, when both
- # down go to down-down. But what if one (or both) is not connected?
- # Still have front/back trees with status? Watch front/status, back/status?
- # up-down: up requested, still down.
- # Back-end watches ./status, front/status
- # Front-end watches ./status, back/status
- # i.e. each watches the other 2.
- # Each is status/request status/actual?
- #
- # backend?
- # frontend?
-
- __exports__ = [
- DBVar('id', ty='int'),
- DBVar('type', ty='str'),
- DBVar('config', ty='sxpr'),
- DBVar('destroyed', ty='bool'),
- ]
-
- def __init__(self, controller, id, config, recreate=False):
- self.controller = controller
- self.id = id
- self.config = config
- self.destroyed = False
- self.type = self.getType()
-
- self.db = controller.getDevDB(id)
-
- def exportToDB(self, save=False):
- self.db.exportToDB(self, fields=self.__exports__, save=save)
-
- def importFromDB(self):
- self.db.importFromDB(self, fields=self.__exports__)
-
- def getDomain(self):
- return self.controller.getDomain()
-
- def getDomainName(self):
- return self.controller.getDomainName()
-
- def getDomainInfo(self):
- return self.controller.getDomainInfo()
-
- def getController(self):
- return self.controller
-
- def getType(self):
- return self.controller.getType()
-
- def getId(self):
- return self.id
-
- def getConfig(self):
- return self.config
-
- def isDestroyed(self):
- return self.destroyed
-
- #----------------------------------------------------------------------------
- # Subclass interface.
- # Define methods in subclass as needed.
- # Redefinitions must have the same arguments.
-
- def init(self, recreate=False, reboot=False):
- """Initialization. Called on initial create (when reboot is False)
- and on reboot (when reboot is True). When xend is restarting is
- called with recreate True. Define in subclass if needed.
-
- Device instance variables must be defined in the class constructor,
- but given null or default values. The real values should be initialised
- in this method. This allows devices to be re-initialised.
-
- Since this can be called to re-initialise a device any state flags
- should be reset.
- """
- self.destroyed = False
-
- def attach(self, recreate=False, change=False):
- """Attach the device to its front and back ends.
- Define in subclass if needed.
- """
- pass
-
- def reboot(self):
- """Reconnect the device when the domain is rebooted.
- """
- self.init(reboot=True)
- self.attach()
-
- def sxpr(self):
- """Get the s-expression for the deivice.
- Implement in a subclass if needed.
-
- @return: sxpr
- """
- return self.getConfig()
-
- def configure(self, config, change=False):
- """Reconfigure the device.
-
- Implement in subclass.
- """
- raise NotImplementedError()
-
- def refresh(self):
- """Refresh the device..
- Default no-op. Define in subclass if needed.
- """
- pass
-
- def destroy(self, change=False, reboot=False):
- """Destroy the device.
- If change is True notify destruction (runtime change).
- If reboot is True the device is being destroyed for a reboot.
- Redefine in subclass if needed.
-
- Called at domain shutdown and when a device is deleted from
- a running domain (with change True).
- """
- self.destroyed = True
- pass
-
- #----------------------------------------------------------------------------
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
+# Copyright (C) 2005 XenSource Ltd
#============================================================================
+
"""Support for virtual network interfaces.
"""
-import random
-
-from xen.util.mac import macFromString, macToString
+import os
from xen.xend import sxp
-from xen.xend import Vifctl
-from xen.xend.XendError import XendError, VmError
-from xen.xend.XendLogging import log
-from xen.xend import XendVnet
-from xen.xend.XendRoot import get_component
-from xen.xend.xenstore import DBVar
-
-from xen.xend.server.controller import Dev, DevController
-
-class NetDev(Dev):
- """A network device.
- """
-
- # State:
- # inherited +
- # ./config
- # ./mac
- # ./be_mac
- # ./bridge
- # ./script
- # ./ipaddr ?
- #
- # ./credit
- # ./period
- #
- # ./vifctl: up/down?
- # ./vifname
- #
- #
- # Poss should have no backend state here - except for ref to backend's own tree
- # for the device? And a status - the one we want.
- # ./back/dom
- # ./back/devid - id for back-end (netif_handle) - same as front/devid
- # ./back/id - backend id (if more than one b/e per domain)
- # ./back/status
- # ./back/tx_shmem_frame - actually these belong in back-end state
- # ./back/rx_shmem_frame
- #
- # ./front/dom
- # ./front/devid
- # ./front/status - need 2: one for requested, one for actual? Or drive from dev status
- # and this is front status only.
- # ./front/tx_shmem_frame
- # ./front/rx_shmem_frame
- #
- # ./evtchn/front - here or in front/back?
- # ./evtchn/back
- # ./evtchn/status ?
- # At present created by dev: but should be created unbound by front/back
- # separately and then bound (by back)?
-
- __exports__ = Dev.__exports__ + [
- DBVar('config', ty='sxpr'),
- DBVar('mac', ty='mac'),
- DBVar('be_mac', ty='mac'),
- DBVar('bridge', ty='str'),
- DBVar('script', ty='str'),
- DBVar('credit', ty='int'),
- DBVar('period', ty='int'),
- DBVar('vifname', ty='str'),
- ]
-
- def __init__(self, controller, id, config, recreate=False):
- Dev.__init__(self, controller, id, config, recreate=recreate)
- self.vif = int(self.id)
- self.status = None
- self.frontendDomain = self.getDomain()
- self.backendDomain = None
- self.credit = None
- self.period = None
- self.mac = None
- self.be_mac = None
- self.bridge = None
- self.script = None
- self.ipaddr = None
- self.mtu = None
- self.vifname = None
- self.configure(self.config, recreate=recreate)
-
- def exportToDB(self, save=False):
- Dev.exportToDB(self, save=save)
-
- def init(self, recreate=False, reboot=False):
- self.destroyed = False
- self.status = NETIF_INTERFACE_STATUS_DISCONNECTED
- self.frontendDomain = self.getDomain()
-
- def _get_config_mac(self, config):
- vmac = sxp.child_value(config, 'mac')
- if not vmac: return None
- try:
- mac = macFromString(vmac)
- except:
- raise XendError("invalid mac: %s" % vmac)
- return mac
-
- def _get_config_be_mac(self, config):
- vmac = sxp.child_value(config, 'be_mac')
- if not vmac: return None
- try:
- mac = macFromString(vmac)
- except:
- raise XendError("invalid backend mac: %s" % vmac)
- return mac
-
- def _get_config_ipaddr(self, config):
- ips = sxp.children(config, elt='ip')
- if ips:
- val = []
- for ipaddr in ips:
- val.append(sxp.child0(ipaddr))
- else:
- val = None
- return val
-
- def _get_config_mtu(self, config):
- mtu = sxp.child_value(config, 'mtu')
- if not mtu: return None
- try:
- mtu = int(mtu)
- except:
- raise XendError("invalid mtu: %s" & mtu)
- return mtu
-
- def configure(self, config, change=False, recreate=False):
- if change:
- return self.reconfigure(config)
- self.config = config
- self.mac = None
- self.be_mac = None
- self.bridge = None
- self.script = None
- self.ipaddr = []
- self.vifname = None
-
- self.vifname = sxp.child_value(config, 'vifname')
- if self.vifname is None:
- self.vifname = self.default_vifname()
- if len(self.vifname) > 15:
- raise XendError('invalid vifname: too long: ' + self.vifname)
- mac = self._get_config_mac(config)
- if mac is None:
- raise XendError("invalid mac")
- self.mac = mac
- self.be_mac = self._get_config_be_mac(config)
- self.bridge = sxp.child_value(config, 'bridge')
- self.script = sxp.child_value(config, 'script')
- self.ipaddr = self._get_config_ipaddr(config) or []
- self.mtu = self._get_config_mtu(config)
- self._config_credit_limit(config)
-
- try:
- if recreate:
- self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
- else:
- #todo: Code below will fail on xend restart when backend is not domain 0.
- xd = get_component('xen.xend.XendDomain')
- self.backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).domid
- except:
- raise XendError('invalid backend domain')
- return self.config
-
- def reconfigure(self, config):
- """Reconfigure the interface with new values.
- Not all configuration parameters can be changed:
- bridge, script and ip addresses can,
- backend and mac cannot.
- To leave a parameter unchanged, omit it from the changes.
+from xen.xend.server.DevController import DevController
- @param config configuration changes
- @return updated interface configuration
- @raise XendError on errors
- """
- changes = {}
- mac = self._get_config_mac(config)
- be_mac = self._get_config_be_mac(config)
- bridge = sxp.child_value(config, 'bridge')
- script = sxp.child_value(config, 'script')
- ipaddr = self._get_config_ipaddr(config)
- mtu = self._get_config_mtu(config)
-
- xd = get_component('xen.xend.XendDomain')
- backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).domid
- if (mac is not None) and (mac != self.mac):
- raise XendError("cannot change mac")
- if (be_mac is not None) and (be_mac != self.be_mac):
- raise XendError("cannot change backend mac")
- if (backendDomain is not None) and (backendDomain != self.backendDomain):
- raise XendError("cannot change backend")
- if (bridge is not None) and (bridge != self.bridge):
- changes['bridge'] = bridge
- if (script is not None) and (script != self.script):
- changes['script'] = script
- if (ipaddr is not None) and (ipaddr != self.ipaddr):
- changes['ipaddr'] = ipaddr
- if (mtu is not None) and (mtu != self.mtu):
- changes['mtu'] = mtu
+next_devid = 1
- if changes:
- self.vifctl("down")
- for (k, v) in changes.items():
- setattr(self, k, v)
- self.config = sxp.merge(config, self.config)
- self.vifctl("up")
- self._config_credit_limit(config, change=True)
- return self.config
-
- def _config_credit_limit(self, config, change=False):
- period = sxp.child_value(config, 'period')
- credit = sxp.child_value(config, 'credit')
- if period and credit:
- try:
- period = int(period)
- credit = int(credit)
- except ex:
- raise XendError('vif: invalid credit limit')
- if change:
- self.setCreditLimit(credit, period)
- self.config = sxp.merge([sxp.name(self.config),
- ['credit', credit],
- ['period', period]],
- self.config)
- else:
- self.period = period
- self.credit = credit
- elif period or credit:
- raise XendError('vif: invalid credit limit')
-
- def sxpr(self):
- vif = str(self.vif)
- mac = self.get_mac()
- val = ['vif',
- ['id', self.id],
- ['vif', vif],
- ['mac', mac],
- ['vifname', self.vifname],
- ]
-
- if self.be_mac:
- val.append(['be_mac', self.get_be_mac()])
- if self.bridge:
- val.append(['bridge', self.bridge])
- if self.script:
- val.append(['script', self.script])
- for ip in self.ipaddr:
- val.append(['ip', ip])
- if self.credit:
- val.append(['credit', self.credit])
- if self.period:
- val.append(['period', self.period])
- return val
-
- def get_vifname(self):
- """Get the virtual interface device name.
- """
- return self.vifname
-
- def default_vifname(self):
- return "vif%d.%d" % (self.frontendDomain, self.vif)
-
- def get_mac(self):
- """Get the MAC address as a string.
- """
- return macToString(self.mac)
-
- def get_be_mac(self):
- """Get the backend MAC address as a string.
- """
- return macToString(self.be_mac)
-
- def vifctl_params(self, vmname=None):
- """Get the parameters to pass to vifctl.
- """
- dom = self.frontendDomain
- if vmname is None:
- xd = get_component('xen.xend.XendDomain')
- try:
- vm = xd.domain_lookup(dom)
- vmname = vm.name
- except:
- vmname = 'Domain-%d' % dom
- return { 'domain': vmname,
- 'vif' : self.get_vifname(),
- 'mac' : self.get_mac(),
- 'bridge': self.bridge,
- 'script': self.script,
- 'ipaddr': self.ipaddr, }
-
- def vifctl(self, op, vmname=None):
- """Bring the device up or down.
- The vmname is needed when bringing a device up for a new domain because
- the domain is not yet in the table so we can't look its name up.
-
- @param op: operation name (up, down)
- @param vmname: vmname
- """
- if op == 'up':
- Vifctl.set_vif_name(self.default_vifname(), self.vifname)
- Vifctl.vifctl(op, **self.vifctl_params(vmname=vmname))
- vnet = XendVnet.instance().vnet_of_bridge(self.bridge)
- if vnet:
- vnet.vifctl(op, self.get_vifname(), self.get_mac())
-
- def attach(self, recreate=False, change=False):
- if recreate:
- pass
- else:
- if self.credit and self.period:
- #self.send_be_creditlimit(self.credit, self.period)
- pass
- self.vifctl('up', vmname=self.getDomainName())
-
- def destroy(self, change=False, reboot=False):
- """Destroy the device's resources and disconnect from the back-end
- device controller. If 'change' is true notify the front-end interface.
-
- @param change: change flag
- """
- self.destroyed = True
- self.status = NETIF_INTERFACE_STATUS_CLOSED
- log.debug("Destroying vif domain=%d vif=%d", self.frontendDomain, self.vif)
- self.vifctl('down')
- if change:
- self.reportStatus()
-
- def setCreditLimit(self, credit, period):
- #todo: these params should be in sxpr and vif config.
- self.credit = credit
- self.period = period
-
- def getCredit(self):
- return self.credit
-
- def getPeriod(self):
- return self.period
-
- def interfaceChanged(self):
- """Notify the front-end that a device has been added or removed.
- """
- pass
-
class NetifController(DevController):
"""Network interface controller. Handles all network devices for a domain.
"""
- def __init__(self, vm, recreate=False):
- DevController.__init__(self, vm, recreate=recreate)
+ def __init__(self, vm):
+ DevController.__init__(self, vm)
- def initController(self, recreate=False, reboot=False):
- self.destroyed = False
- if reboot:
- self.rebootDevices()
- def destroyController(self, reboot=False):
- """Destroy the controller and all devices.
- """
- self.destroyed = True
- log.debug("Destroying netif domain=%d", self.getDomain())
- self.destroyDevices(reboot=reboot)
+ def getDeviceDetails(self, config):
+ """@see DevController.getDeviceDetails"""
- def sxpr(self):
- val = ['netif', ['dom', self.getDomain()]]
- return val
-
- def newDevice(self, id, config, recreate=False):
- """Create a network device.
+ global next_devid
- @param id: interface id
- @param config: device configuration
- @param recreate: recreate flag (true after xend restart)
- """
- return NetDev(self, id, config, recreate=recreate)
+ from xen.xend import XendRoot
+ xroot = XendRoot.instance()
- def limitDevice(self, vif, credit, period):
- if vif not in self.devices:
- raise XendError('device does not exist for credit limit: vif'
- + str(self.getDomain()) + '.' + str(vif))
-
- dev = self.devices[vif]
- return dev.setCreditLimit(credit, period)
+ def _get_config_ipaddr(config):
+ val = []
+ for ipaddr in sxp.children(config, elt='ip'):
+ val.append(sxp.child0(ipaddr))
+ return val
+
+ devid = next_devid
+ next_devid += 1
+
+ script = os.path.join(xroot.network_script_dir,
+ sxp.child_value(config, 'script',
+ xroot.get_vif_script()))
+ bridge = sxp.child_value(config, 'bridge',
+ xroot.get_vif_bridge())
+ mac = sxp.child_value(config, 'mac')
+ ipaddr = _get_config_ipaddr(config)
+
+ back = { 'script' : script,
+ 'mac' : mac,
+ 'bridge' : bridge,
+ 'handle' : "%i" % devid }
+ if ipaddr:
+ back['ip'] = ' '.join(ipaddr)
+
+ front = { 'handle' : "%i" % devid,
+ 'mac' : mac }
+
+ return (devid, back, front)
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
+# Copyright (C) 2005 XenSource Ltd
#============================================================================
+
import types
-import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
+import xen.lowlevel.xc;
from xen.xend import sxp
from xen.xend.XendError import VmError
-from controller import Dev, DevController
+from xen.xend.server.DevController import DevController
+
+
+xc = xen.lowlevel.xc.new()
+
def parse_pci(val):
"""Parse a pci field.
v = val
return v
-class PciDev(Dev):
-
- def __init__(self, controller, id, config, recreate=False):
- Dev.__init__(self, controller, id, config, recreate=recreate)
- bus = sxp.child_value(self.config, 'bus')
- if not bus:
- raise VmError('pci: Missing bus')
- dev = sxp.child_value(self.config, 'dev')
- if not dev:
- raise VmError('pci: Missing dev')
- func = sxp.child_value(self.config, 'func')
- if not func:
- raise VmError('pci: Missing func')
- try:
- bus = parse_pci(bus)
- dev = parse_pci(dev)
- func = parse_pci(func)
- except:
- raise VmError('pci: invalid parameter')
-
- def attach(self, recreate=False, change=False):
+
+class PciController(DevController):
+
+ def __init__(self, vm):
+ DevController.__init__(self, vm)
+
+
+ def getDeviceDetails(self, config):
+ """@see DevController.getDeviceDetails"""
+
+ def get_param(field):
+ try:
+ val = sxp.child_value(config, field)
+
+ if not val:
+ raise VmError('pci: Missing %s config setting' % field)
+
+ return parse_pci(val)
+ except:
+ raise VmError('pci: Invalid config setting %s: %s' %
+ (field, val))
+
+ bus = get_param('bus')
+ dev = get_param('dev')
+ func = get_param('func')
+
rc = xc.physdev_pci_access_modify(dom = self.getDomain(),
bus = bus,
dev = dev,
enable = True)
if rc < 0:
#todo non-fatal
- raise VmError('pci: Failed to configure device: bus=%s dev=%s func=%s' %
- (bus, dev, func))
-
- def destroy(self, change=False, reboot=False):
- pass
-
-class PciController(DevController):
+ raise VmError(
+ 'pci: Failed to configure device: bus=%s dev=%s func=%s' %
+ (bus, dev, func))
- def newDevice(self, id, config, recreate=False):
- return PciDev(self, id, config, recreate=recreate)
+ return (dev, {}, {})
-# Copyright (C) 2005 IBM Corporation
-# Authort: Stefan Berger, stefanb@us.ibm.com
-# Derived from netif.py:
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+# Copyright (C) 2005 IBM Corporation
+# Author: Stefan Berger, stefanb@us.ibm.com
+# Copyright (C) 2005 XenSource Ltd
+#============================================================================
+
"""Support for virtual TPM interfaces.
"""
-import random
-
from xen.xend import sxp
-from xen.xend.XendError import XendError, VmError
from xen.xend.XendLogging import log
-from xen.xend.XendRoot import get_component
-from xen.xend.xenstore import DBVar
-from xen.xend.server.controller import Dev, DevController
+from xen.xend.server.DevController import DevController
+
class TPMifController(DevController):
"""TPM interface controller. Handles all TPM devices for a domain.
"""
- def __init__(self, vm, recreate=False):
- DevController.__init__(self, vm, recreate=recreate)
-
- def initController(self, recreate=False, reboot=False):
- self.destroyed = False
+ def __init__(self, vm):
+ DevController.__init__(self, vm)
- def destroyController(self, reboot=False):
- """Destroy the controller and all devices.
- """
- self.destroyed = True
- self.destroyDevices(reboot=reboot)
- def sxpr(self):
- val = ['tpmif', ['dom', self.getDomain()]]
- return val
+ def getDeviceDetails(self, config):
+ """@see DevController.getDeviceDetails"""
+
+ devid = int(sxp.child_value(config, 'instance', '0'))
+ log.error("The domain has a TPM with instance %d." % devid)
- def newDevice(self, id, config, recreate=False):
- """Create a TPM device.
+ back = { 'instance' : "%i" % devid }
+ front = { 'handle' : "%i" % devid }
- @param id: interface id
- @param config: device configuration
- @param recreate: recreate flag (true after xend restart)
- """
- return None
+ return (devid, back, front)
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
# Copyright (C) 2004 Intel Research Cambridge
# Copyright (C) 2004 Mark Williamson <mark.williamson@cl.cam.ac.uk>
-"""Support for virtual USB hubs.
-"""
-
-from xen.xend import sxp
-from xen.xend.XendLogging import log
-from xen.xend.XendError import XendError
-from xen.xend.xenstore import DBVar
-
-from xen.xend.server.controller import Dev, DevController
-
-class UsbBackend:
- """Handler for the 'back-end' channel to a USB device driver domain
- on behalf of a front-end domain.
- """
- def __init__(self, controller, id, dom):
- self.controller = controller
- self.id = id
- self.destroyed = False
- self.connected = False
- self.connecting = False
- self.frontendDomain = self.controller.getDomain()
- self.backendDomain = dom
-
- def init(self, recreate=False, reboot=False):
- pass
-
- def __str__(self):
- return ('<UsbifBackend frontend=%d backend=%d id=%d>'
- % (self.frontendDomain,
- self.backendDomain,
- self.id))
-
- def connect(self, recreate=False):
- """Connect the controller to the usbif control interface.
-
- @param recreate: true if after xend restart
- """
- log.debug("Connecting usbif %s", str(self))
- if recreate or self.connected or self.connecting:
- pass
-
- def destroy(self, reboot=False):
- """Disconnect from the usbif control interface and destroy it.
- """
- self.destroyed = True
-
- def interfaceChanged(self):
- pass
-
-
-class UsbDev(Dev):
+# Copyright (C) 2005 XenSource Ltd
+#============================================================================
- __exports__ = Dev.__exports__ + [
- DBVar('port', ty='int'),
- DBVar('path', ty='str'),
- ]
-
- def __init__(self, controller, id, config, recreate=False):
- Dev.__init__(self, controller, id, config, recreate=recreate)
- self.port = id
- self.path = None
- self.frontendDomain = self.getDomain()
- self.backendDomain = 0
- self.configure(self.config, recreate=recreate)
-
- def init(self, recreate=False, reboot=False):
- self.destroyed = False
- self.frontendDomain = self.getDomain()
-
- def configure(self, config, change=False, recreate=False):
- if change:
- raise XendError("cannot reconfigure usb")
- #todo: FIXME: Use sxp access methods to get this value.
- # Must not use direct indexing.
- self.path = config[1][1]
-
- #todo: FIXME: Support configuring the backend domain.
-## try:
-## self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
-## except:
-## raise XendError('invalid backend domain')
-
- def attach(self, recreate=False, change=False):
- if recreate:
- pass
- else:
- self.attachBackend()
- if change:
- self.interfaceChanged()
-
- def sxpr(self):
- val = ['usb',
- ['id', self.id],
- ['port', self.port],
- ['path', self.path],
- ]
- return val
-
- def getBackend(self):
- return self.controller.getBackend(self.backendDomain)
- def destroy(self, change=False, reboot=False):
- """Destroy the device. If 'change' is true notify the front-end interface.
+"""Support for virtual USB hubs.
+"""
- @param change: change flag
- """
- self.destroyed = True
- log.debug("Destroying usb domain=%d id=%s", self.frontendDomain, self.id)
- if change:
- self.interfaceChanged()
+from xen.xend.server.DevController import DevController
- def interfaceChanged(self):
- """Tell the back-end to notify the front-end that a device has been
- added or removed.
- """
- self.getBackend().interfaceChanged()
- def attachBackend(self):
- """Attach the device to its controller.
+next_devid = 1
- """
- self.getBackend().connect()
class UsbifController(DevController):
"""USB device interface controller. Handles all USB devices
for a domain.
"""
- def __init__(self, vm, recreate=False):
+ def __init__(self, vm):
"""Create a USB device controller.
"""
- DevController.__init__(self, vm, recreate=recreate)
- self.backends = {}
- self.backendId = 0
+ DevController.__init__(self, vm)
- def init(self, recreate=False, reboot=False):
- self.destroyed = False
- if reboot:
- self.rebootBackends()
- self.rebootDevices()
- def sxpr(self):
- val = ['usbif',
- ['dom', self.getDomain()]]
- return val
+ def getDeviceDetails(self, _):
+ """@see DevController.getDeviceDetails"""
- def newDevice(self, id, config, recreate=False):
- return UsbDev(self, id, config, recreate=recreate)
-
- def destroyController(self, reboot=False):
- """Destroy the controller and all devices.
- """
- self.destroyed = True
- log.debug("Destroying blkif domain=%d", self.getDomain())
- self.destroyDevices(reboot=reboot)
- self.destroyBackends(reboot=reboot)
+ global next_devid
- def rebootBackends(self):
- for backend in self.backends.values():
- backend.init(reboot=True)
+ devid = next_devid
+ next_devid += 1
- def getBackendById(self, id):
- return self.backends.get(id)
-
- def getBackendByDomain(self, dom):
- for backend in self.backends.values():
- if backend.backendDomain == dom:
- return backend
- return None
-
- def getBackend(self, dom):
- backend = self.getBackendByDomain(dom)
- if backend: return backend
- backend = UsbBackend(self, self.backendId, dom)
- self.backendId += 1
- self.backends[backend.getId()] = backend
- backend.init()
- return backend
-
- def destroyBackends(self, reboot=False):
- for backend in self.backends.values():
- backend.destroy(reboot=reboot)
+ return (devid, {}, {})